//    Copyright (C) Clear Office.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO.Packaging;
using Office.Core.Serialization;
using Office.Spreadsheet.Data;
using Office.Spreadsheet.Serialization;

namespace Office.Spreadsheet.PivotTable
{
    internal class PivotTableDefinition : IOfficeXmlSerializable
    {
        private bool _asteriskTotals;
        private int _cacheId;
        internal int CacheId { get { return _cacheId; } }

        public PivotCacheDefinition PivotCacheDefinition
        {
            get { return _pivotCacheDefinition; }
        }

        private int _chartFormat;
        private List<ChartFormat> _chartFormats = new List<ChartFormat>();
        private List<Field> _colFields = new List<Field>();
        private bool _colGrandTotals;
        private string _colHeaderCaption;
        private ColumnHierarchiesUsage _colHierarchiesUsage;
        private List<RowColumnItem> _colItems = new List<RowColumnItem>();
        private bool _compact;
        private bool _compactData = true;
        private List<ConditionalFormat> _conditionalFormats = new List<ConditionalFormat>();
        private int _createdVersion;
        private bool _customListSort;
        private string _dataCaption;
        private List<DataField> _dataFields = new List<DataField>();
        private bool _dataOnRows;
        private int? _dataPosition;
        private bool _disableFieldList;
        private bool _editData;
        private bool _enableDrill;
        private bool _enableFieldProperties;
        private bool _enableWizard;
        private string _errorCaption;
        private ExtensionElement _extLst;
        private bool _fieldListSortAscending;
        private bool _fieldPrintTitles;
        private readonly List<PivotFilter> _filters = new List<PivotFilter>();
        private readonly List<PivotTableFormat> _formats = new List<PivotTableFormat>();
        public List<PivotTableFormat> Formats { get { return _formats; } }
        private string _grandTotalCaption;
        private bool _gridDropZones;
        private bool _immersive;
        private int _indent;
        private bool _itemPrintTitles;
        private Location _location;
        private bool _mdxSubqueries;
        private bool _mergeItem;
        private int _minRefreshableVersion;
        private string _missingCaption;
        private bool _multipleFieldFilters;
        private string _name;
        private bool _outline;
        private bool _outlineData;
        private List<PageField> _pageFields = new List<PageField>();
        private bool _pageOverThenDown;
        private string _pageStyle;
        private int _pageWrap;
        private List<PivotField> _pivotFields = new List<PivotField>();
        private List<PivotHierarchy> _pivotHierarchies = new List<PivotHierarchy>();
        private string _pivotTableStyle;
        private PivotTableStyle _pivotTableStyleInfo;
        private bool _preserveFormatting;
        private bool _printDrill;
        private bool _published;
        private List<Field> _rowFields = new List<Field>();
        private bool _rowGrandTotals;
        private string _rowHeaderCaption;
        private RowHiecharchiesUsage _rowHierarchiesUsage;
        private List<RowColumnItem> _rowItems = new List<RowColumnItem>();
        private bool _showCalcMbrs;
        private bool _showDataDropDown;
        private bool _showDataTips;
        private bool _showDrill;
        private bool _showDropZones;
        private bool _showEmptyCol;
        private bool _showEmptyRow;
        private bool _showError;
        private bool _showHeaders;
        private bool _showItems;
        private bool _showMemberPropertyTips;
        private bool _showMissing;
        private bool _showMultipleLabel;
        private bool _subtotalHiddenItems;
        private string _tag;
        private int _updatedVersion;
        private bool _useAutoFormatting;
        private string _vacatedStyle;
        private bool _visualTotals;
        private AGAutoFormat agAutoFormat = new AGAutoFormat();
        private string xmlName = "pivotTableDefinition";
        private PivotCacheDefinition _pivotCacheDefinition;

        #region IOfficeXmlSerializable Members

        public void ReadXml(ReadContext context)
        {
            using (ReadContext c = context.Read(xmlName))
            {
                agAutoFormat.ReadXml(c);
                _name = c.GetString("name");
                _cacheId = c.GetUIntegerAsInteger("cacheId");
                _dataOnRows = c.GetOptionalBoolean("dataOnRows", false);
                _dataPosition = c.GetOptionalInteger("dataPosition");
                agAutoFormat.ReadXml(context);
                // missing AG_AutoFormat
                _dataCaption = c.GetString("dataCaption");
                _grandTotalCaption = c.GetOptionalString("grandTotalCaption");
                _errorCaption = c.GetOptionalString("errorCaption");
                _showError = c.GetOptionalBoolean("showError", false);
                _missingCaption = c.GetOptionalString("missingCaption");
                _showMissing = c.GetOptionalBoolean("showMissing", true);
                _pageStyle = c.GetOptionalString("pageStyle");
                _pivotTableStyle = c.GetOptionalString("pivotTableStyle");
                _vacatedStyle = c.GetOptionalString("vacatedStyle");
                _tag = c.GetOptionalString("tag");
                _updatedVersion = c.GetOptionalInteger("updatedVersion", 0);
                _minRefreshableVersion = c.GetOptionalInteger("minRefreshableVersion", 0);
                _asteriskTotals = c.GetOptionalBoolean("asteriskTotals", false);
                _showItems = c.GetOptionalBoolean("showItems", true);
                _editData = c.GetOptionalBoolean("editData", false);
                _disableFieldList = c.GetOptionalBoolean("disableFieldList", false);
                _showCalcMbrs = c.GetOptionalBoolean("showCalcMbrs", true);
                _visualTotals = c.GetOptionalBoolean("visualTotals", true);
                _showMultipleLabel = c.GetOptionalBoolean("showMultipleLabel", true);
                _showDataDropDown = c.GetOptionalBoolean("showDataDropDown", true);
                _showDrill = c.GetOptionalBoolean("showDrill", true);
                _printDrill = c.GetOptionalBoolean("printDrill", false);
                _showMemberPropertyTips = c.GetOptionalBoolean("showMemberPropertyTips", true);
                _showDataTips = c.GetOptionalBoolean("showDataTips", true);
                _enableWizard = c.GetOptionalBoolean("enableWizard", true);
                _enableDrill = c.GetOptionalBoolean("enableDrill", true);
                _enableFieldProperties = c.GetOptionalBoolean("enableFieldProperties", true);
                _preserveFormatting = c.GetOptionalBoolean("preserveFormatting", true);
                _useAutoFormatting = c.GetOptionalBoolean("useAutoFormatting", false);
                _pageWrap = c.GetOptionalInteger("pageWrap", 0);
                _pageOverThenDown = c.GetOptionalBoolean("pageOverThenDown", false);
                _subtotalHiddenItems = c.GetOptionalBoolean("subtotalHiddenItems", false);
                _rowGrandTotals = c.GetOptionalBoolean("rowGrandTotals", true);
                _colGrandTotals = c.GetOptionalBoolean("colGrandTotals", true);
                _fieldPrintTitles = c.GetOptionalBoolean("fieldPrintTitles", false);
                _itemPrintTitles = c.GetOptionalBoolean("itemPrintTitles", false);
                _mergeItem = c.GetOptionalBoolean("mergeItem", false);
                _showDropZones = c.GetOptionalBoolean("showDropZones", true);
                _createdVersion = c.GetOptionalInteger("createdVersion", 0);
                _indent = c.GetOptionalInteger("indent", 1);
                _showEmptyRow = c.GetOptionalBoolean("showEmptyRow", false);
                _showEmptyCol = c.GetOptionalBoolean("showEmptyCol", false);
                _showHeaders = c.GetOptionalBoolean("showHeaders", true);
                _compact = c.GetOptionalBoolean("compact", true);
                _outline = c.GetOptionalBoolean("outline", false);
                _outlineData = c.GetOptionalBoolean("outlineData", false);
                _compactData = c.GetOptionalBoolean("compactData", true);
                _published = c.GetOptionalBoolean("published", false);
                _gridDropZones = c.GetOptionalBoolean("gridDropZones", false);
                _immersive = c.GetOptionalBoolean("immersive", true);
                _multipleFieldFilters = c.GetOptionalBoolean("multipleFieldFilters", true);
                _chartFormat = c.GetOptionalInteger("chartFormat", 0);
                _rowHeaderCaption = c.GetOptionalString("rowHeaderCaption");
                _colHeaderCaption = c.GetOptionalString("colHeaderCaption");
                _fieldListSortAscending = c.GetOptionalBoolean("fieldListSortAscending", false);
                _mdxSubqueries = c.GetOptionalBoolean("mdxSubqueries", false);
                _customListSort = c.GetOptionalBoolean("customListSort", true);


                _location = c.ReadElement<Location>();
                _pivotFields.Clear();
                _pivotFields.AddRange(c.ReadElements<PivotField>("pivotFields", "pivotField"));
                _rowFields.AddRange(c.ReadOptionalListElement<Field>("rowFields", "field"));
                _rowItems.AddRange(c.ReadOptionalListElement<RowColumnItem>("rowItems", "i"));
                _colFields.AddRange(c.ReadOptionalListElement<Field>("colFields", "field"));
                _colItems.AddRange(c.ReadOptionalListElement<RowColumnItem>("colItems", "i"));
                _pageFields.Clear();
                _pageFields.AddRange(c.ReadOptionalListElement<PageField>("pageFields", "pageField"));
                _dataFields.Clear();
                _dataFields.AddRange(c.ReadOptionalListElement<DataField>("dataFields", "dataField"));
                _formats.Clear();
                _formats.AddRange(c.ReadOptionalListElement<PivotTableFormat>("formats", "format"));
                _conditionalFormats.Clear();
                _conditionalFormats.AddRange(c.ReadOptionalListElement<ConditionalFormat>("conditionalFormats",
                                                                                          "conditionalFormat"));
                _chartFormats.Clear();
                _chartFormats.AddRange(c.ReadOptionalListElement<ChartFormat>("chartFormats", "chartFormat"));
                _pivotHierarchies.Clear();
                _pivotHierarchies.AddRange(c.ReadOptionalListElement<PivotHierarchy>("pivotHierarchies",
                                                                                     "pivotHierarchy"));
                _pivotTableStyleInfo = c.ReadOptionalElement<PivotTableStyle>("pivotTableStyleInfo");
                _filters.Clear();
                _filters.AddRange(c.ReadOptionalListElement<PivotFilter>("filters", "filter"));
                _rowHierarchiesUsage = c.ReadOptionalElement<RowHiecharchiesUsage>("rowHierarchiesUsage");
                _colHierarchiesUsage = c.ReadOptionalElement<ColumnHierarchiesUsage>("colHierarchiesUsage");
                _extLst = c.ReadOptionalElement<ExtensionElement>("extLst");
                PackageRelationship relationship =
    Enumerable.FirstOrDefault(
        context.Part.GetRelationshipsByType(SpreadsheetConstants.PivotCacheDefinitionType));
                if (relationship != null)
                using (var c2 = c.OpenRelatedContext(relationship, c.NamespaceUri))
                {
                    this._pivotCacheDefinition = c2.ReadElement<PivotCacheDefinition>();
                }

            }
        }

        public void WriteXml(WriteContext context)
        {
            using (WriteContext c = context.Write(xmlName))
            {
                PivotCacheManager res = c.GetData<PivotCacheManager>();
                c.SetString("name", _name);
                _cacheId = res.GetNextId();
                c.SetInteger("cacheId", _cacheId);
                c.SetOptionalBoolean("dataOnRows", _dataOnRows, false);
                c.SetOptionalInteger("dataPosition", _dataPosition);
                c.SetString("dataCaption", _dataCaption);
                c.SetOptionalString("grandTotalCaption", _grandTotalCaption);
                c.SetOptionalString("errorCaption", _errorCaption);
                c.SetOptionalBoolean("showError", _showError, false);
                c.SetOptionalString("missingCaption", _missingCaption);
                c.SetOptionalBoolean("showMissing", _showMissing, true);
                c.SetOptionalString("pageStyle", _pageStyle);
                c.SetOptionalString("pivotTableStyle", _pivotTableStyle);
                c.SetOptionalString("vacatedStyle", _vacatedStyle);
                c.SetOptionalString("tag", _tag);
                c.SetOptionalInteger("updatedVersion", _updatedVersion, 0);
                c.SetOptionalInteger("minRefreshableVersion", _minRefreshableVersion, 0);
                c.SetOptionalBoolean("asteriskTotals", _asteriskTotals, false);
                c.SetOptionalBoolean("showItems", _showItems, true);
                c.SetOptionalBoolean("editData", _editData, false);
                c.SetOptionalBoolean("disableFieldList", _disableFieldList, false);
                c.SetOptionalBoolean("showCalcMbrs", _showCalcMbrs, true);
                c.SetOptionalBoolean("visualTotals", _visualTotals, true);
                c.SetOptionalBoolean("showMultipleLabel", _showMultipleLabel, true);
                c.SetOptionalBoolean("showDataDropDown", _showDataDropDown, true);
                c.SetOptionalBoolean("showDrill", _showDrill, true);
                c.SetOptionalBoolean("printDrill", _printDrill, false);
                c.SetOptionalBoolean("showMemberPropertyTips", _showMemberPropertyTips, true);
                c.SetOptionalBoolean("showDataTips", _showDataTips, true);
                c.SetOptionalBoolean("enableWizard", _enableWizard, true);
                c.SetOptionalBoolean("enableDrill", _enableDrill, true);
                c.SetOptionalBoolean("enableFieldProperties", _enableFieldProperties, true);
                c.SetOptionalBoolean("preserveFormatting", _preserveFormatting, true);
                c.SetOptionalBoolean("useAutoFormatting", _useAutoFormatting, false);
                c.SetOptionalInteger("pageWrap", _pageWrap, 0);
                c.SetOptionalBoolean("pageOverThenDown", _pageOverThenDown, false);
                c.SetOptionalBoolean("subtotalHiddenItems", _subtotalHiddenItems, false);
                c.SetOptionalBoolean("rowGrandTotals", _rowGrandTotals, true);
                c.SetOptionalBoolean("colGrandTotals", _colGrandTotals, true);
                c.SetOptionalBoolean("fieldPrintTitles", _fieldPrintTitles, false);
                c.SetOptionalBoolean("itemPrintTitles", _itemPrintTitles, false);
                c.SetOptionalBoolean("mergeItem", _mergeItem, false);
                c.SetOptionalBoolean("showDropZones", _showDropZones, true);
                c.SetOptionalInteger("createdVersion", _createdVersion, 0);
                c.SetOptionalInteger("indent", _indent, 1);
                c.SetOptionalBoolean("showEmptyRow", _showEmptyRow, false);
                c.SetOptionalBoolean("showEmptyCol", _showEmptyCol, false);
                c.SetOptionalBoolean("showHeaders", _showHeaders, true);
                c.SetOptionalBoolean("compact", _compact, true);
                c.SetOptionalBoolean("outline", _outline, false);
                c.SetOptionalBoolean("outlineData", _outlineData, false);
                c.SetOptionalBoolean("compactData", _compactData, true);
                c.SetOptionalBoolean("published", _published, false);
                c.SetOptionalBoolean("gridDropZones", _gridDropZones, false);
                c.SetOptionalBoolean("immersive", _immersive, true);
                c.SetOptionalBoolean("multipleFieldFilters", _multipleFieldFilters, true);
                c.SetOptionalInteger("chartFormat", _chartFormat, 0);
                c.SetOptionalString("rowHeaderCaption", _rowHeaderCaption);
                c.SetOptionalString("colHeaderCaption", _colHeaderCaption);
                c.SetOptionalBoolean("fieldListSortAscending", _fieldListSortAscending, false);
                c.SetOptionalBoolean("mdxSubqueries", _mdxSubqueries, false);
                c.SetOptionalBoolean("customListSort", _customListSort, true);
                c.WriteElement(_location);
                WriteItems(c, "pivotFields", _pivotFields);
                WriteItems(c, "rowFields", _rowFields);
                WriteItems(c, "rowItems", _rowItems);
                WriteItems(c, "colFields", _colFields);
                WriteItems(c, "colItems", _colItems);
                WriteItems(c, "pageFields", _pageFields);
                WriteItems(c, "dataFields", _dataFields);
                WriteItems(c, "formats", _formats);
                WriteItems(c, "conditionalFormats", _conditionalFormats);
                WriteItems(c, "chartFormats", _chartFormats);
                WriteItems(c, "pivotHierarchies", _pivotHierarchies);
                c.WriteOptionalElement(_pivotTableStyleInfo);
                WriteItems(c, "filters", _filters);
                c.WriteOptionalElement(_rowHierarchiesUsage);
                c.WriteOptionalElement(_colHierarchiesUsage);
                c.WriteOptionalElement(_extLst);
                if (PivotCacheDefinition != null)
                {
                    using (var c2 = c.CreateRelatedContext(null, c.NamespaceUri, c.GetAvailableUri("/xl/pivotCache/pivotCacheDefinition{0}.xml"),
                        SpreadsheetConstants.PivotCacheDefinitionType, SpreadsheetConstants.PivotCacheDefinitionContentType))
                    {
                        c2.WriteElement(PivotCacheDefinition);
                        res.Add(PivotCacheDefinition, c2.Part.Uri);
                    }
                }
            }
        }

        #endregion

        private static void WriteItems<T>(WriteContext context, string names, ICollection<T> items) where T : IOfficeXmlSerializable
        {
            Contract.Requires(items != null);
            if (items.Count == 0)
                return;
            using (WriteContext c2 = context.Write(names))
            {
                c2.SetInteger("count", items.Count);
                c2.WriteElements(items);
            }
        }
    }


    internal class ConditionalFormat : IOfficeXmlSerializable
    {
        #region IOfficeXmlSerializable Members

        public void ReadXml(ReadContext context)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(WriteContext context)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    internal class PivotHierarchy : IOfficeXmlSerializable
    {
        #region IOfficeXmlSerializable Members

        public void ReadXml(ReadContext context)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(WriteContext context)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    internal class PivotFilter : IOfficeXmlSerializable
    {
        #region IOfficeXmlSerializable Members

        public void ReadXml(ReadContext context)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(WriteContext context)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    internal class RowHiecharchiesUsage : IOfficeXmlSerializable
    {
        #region IOfficeXmlSerializable Members

        public void ReadXml(ReadContext context)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(WriteContext context)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    internal class ColumnHierarchiesUsage : IOfficeXmlSerializable
    {
        #region IOfficeXmlSerializable Members

        public void ReadXml(ReadContext context)
        {
            throw new NotImplementedException();
        }

        public void WriteXml(WriteContext context)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}